package wangwenjun.phase2.concurrencypattern.threadmonitor;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import util.ThreadUtil;

/**
 * {@link ReturnRunnableNotifierTask}应该保持了与Thread相同的使用习惯
 * @see Runnable
 * @author ChangLiang
 * @date 2020/6/12
 */
@Slf4j
public final class ReturnRunnableNotifierTask<T> extends Thread implements ReturnRunnableNotifier {

    /**
     * 观察者模式中的Notifier持有Listener 严格意义上的观察者模式是需要Listener集合
     */
    private final ReturnRunnableStateListener<T> returnRunnableStateListener;

    private final ReturnRunnable<T> task;

    private RETURN_RUNNABLE_STATE returnRunnableStateEnum;

    private static final String DEFAULT_THREAD_NAME = "my-runnable-listenable-task";

    public ReturnRunnableNotifierTask(ReturnRunnable<T> task) {
        this(new ReturnRunnableStateListener.EmptyReturnRunnableStateListener<>(), task, DEFAULT_THREAD_NAME);
    }

    /**
     * 在构造期间需要传入Task 的具体实现
     * @param runnableStateExecutor
     * @param task
     */
    public ReturnRunnableNotifierTask(ReturnRunnableStateListener<T> runnableStateExecutor, ReturnRunnable<T> task, String threadName) {
        if (task == null) {
            throw new IllegalArgumentException("The task is required");
        }
        super.setName(StringUtils.isEmpty(threadName)?DEFAULT_THREAD_NAME:threadName);
        this.returnRunnableStateListener = runnableStateExecutor;
        this.task = task;
    }

    /**
     * notify 方法用于通知事件的监听者，此时任务在执行过程中发生了什么，最主要的通知是异常的处理。
     * @param runnable_state
     * @param result
     * @param e
     */
    private void notify(RETURN_RUNNABLE_STATE runnable_state, T result, Exception e) {
        if (runnable_state == null) {
            return;
        }
        this.returnRunnableStateEnum = runnable_state;
        try {
            switch (runnable_state) {
                case STARTED:
                    this.returnRunnableStateListener.onStart(Thread.currentThread());
                    break;
                case RUNNING:
                    this.returnRunnableStateListener.onRunning(Thread.currentThread());
                    break;
                case FINISHED:
                    this.returnRunnableStateListener.onFinish(Thread.currentThread(), result);
                    break;
                case ERROR:
                    this.returnRunnableStateListener.onError(Thread.currentThread(), e);
                    break;
                default:
                    break;
            }
        } catch (Exception e1) {
            if (runnable_state == RETURN_RUNNABLE_STATE.ERROR) {
                /**
                 * 如果任务执行过程中出现错误并且抛出了异常，那么notify方法就不能忽略该异常，需要继续抛出异常，保持与call方法同样的意图
                 */
                throw e1;
            } else {
                /**
                 * 如果监听者Listener在响应某个事件的过程中出现了意外，则会导致任务的正常执行受到影响
                 * 因此需要进行异常捕获，并忽略这些异常信息以保证Listener的实现不影响任务的正确执行，
                 */
                log.error("listener error");
                log.error(ThreadUtil.exceptionToString(e1));
            }
        }
    }

    /**
     * 重写父类的run方法，并且将其修饰为final类型，不允许子类再次对其进行重写，
     * run方法在线程的运行期间，可监控任务在执行过程中的各个生命周期阶段，任务每经过一个阶段相当于发生了一次事件
     */
    @Override
    public final void run() {
        // 在执行线程逻辑单元的时候，分别触发相应的事件
        this.notify(RETURN_RUNNABLE_STATE.STARTED,null,null);
        try {
            this.notify(RETURN_RUNNABLE_STATE.RUNNING,null,null);
            // 将真正的业务逻辑执行单元交给了一个可返回计算结果的接口ReturnRunnable
            T result = this.task.call();
            this.notify(RETURN_RUNNABLE_STATE.FINISHED,result,null);
        } catch (Exception e) {
            this.notify(RETURN_RUNNABLE_STATE.ERROR,null,e);
        }
    }
}
